﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using OpenNETCF.Security.Cryptography;
using System.Security.Cryptography;
using System.Web;
using foursquare.Foursquare;
using System.Drawing;

namespace foursquare
{
    class FS
    {
        public static string OAuthToken = "";
        public static string OAuthTokenSecret = "";

        private static Encoding encode = System.Text.Encoding.GetEncoding("utf-8");

        private const string API_HOST = "http://api.foursquare.com/v1/";
        private const string API_HISTORY = "history";
        private const string API_CITIES = "cities";
        private const string API_CHECKCITY = "checkcity";
        private const string API_CHECKINS = "checkins";
        private const string API_VENUES = "venues";
        private const string API_VENUE = "venue";
        private const string API_CHECKIN = "checkin";
        private const string API_FRIENDS = "friends";
        private const string API_ADDVENUE = "addvenue";
        private const string API_USER = "user";
        private const string API_TIPS = "tips";
        private const string API_ADDTIP = "addtip";

        private const string API_FORMAT = ".json";

        private const string METHOD_POST = "POST";
        private const string METHOD_GET = "GET";

        public static Venue GetVenue(int vid)
        {
            List<string> parameters = new List<string>();
            parameters.Add("vid=" + vid);

            string json = APIRequest(API_VENUE, METHOD_GET, parameters);
            JObject jsonObject = JObject.Parse(json);
            Venue v = JsonConvert.DeserializeObject<Venue>(jsonObject["venue"].ToString());
            return v;
        }

        public static Tip AddTip(int vid, string text, string type)
        {
            List<string> parameters = new List<string>();
            parameters.Add("vid=" + vid);
            parameters.Add("text=" + text);
            if (!String.IsNullOrEmpty(type)) parameters.Add("type=" + type);

            string json = APIRequest(API_ADDTIP, METHOD_POST, parameters);
            JObject jsonObject = JObject.Parse(json);
            Tip t = JsonConvert.DeserializeObject<Tip>(jsonObject["tip"].ToString());
            return t;
        }

        public static List<Tip> GetTips(double geolat, double geolong, int l)
        {
            List<string> parameters = new List<string>();
            parameters.Add("geolat=" + geolat);
            parameters.Add("geolong=" + geolong);
            if (l > 0) parameters.Add("l=" + l);

            string json = APIRequest(API_TIPS, METHOD_GET, parameters);
            JObject jsonObject = JObject.Parse(json);
            List<Tip> t = JsonConvert.DeserializeObject<List<Tip>>(jsonObject["group"][0]["tips"].ToString());
            return t;
        }

        public static User GetUser(int uid, int showBadges, int showMayor)
        {
            List<string> parameters = new List<string>();
            parameters.Add("uid=" + uid);
            if (showBadges > 0) parameters.Add("badges=" + showBadges);
            if (showMayor > 0) parameters.Add("mayor=" + showMayor);
            
            string json = APIRequest(API_USER, METHOD_GET, parameters);
            JObject jsonObject = JObject.Parse(json);
            User u = JsonConvert.DeserializeObject<User>(jsonObject["user"].ToString());
            return u;
        }

        public static User GetSelf()
        {
            List<string> parameters = new List<string>();

            string json = APIRequest(API_USER, METHOD_GET, parameters);
            JObject jsonObject = JObject.Parse(json);
            User u = JsonConvert.DeserializeObject<User>(jsonObject["user"].ToString());
            return u;
        }

        public static List<City> GetCities()
        {
            List<string> parameters = new List<string>();

            string json = APIRequest(API_CITIES, METHOD_GET, parameters);
            JObject jsonObject = JObject.Parse(json);
            List<City> cities = JsonConvert.DeserializeObject<List<City>>(jsonObject["cities"].ToString());
            return cities;
        }

        //name - the name of the venue
        //address - the address of the venue (e.g., "202 1st Avenue")
        //crossstreet - the cross streets (e.g., "btw Grand & Broome")
        //city - the city name where this venue is
        //state - the state where the city is
        //zip - (optional) the ZIP code for the venue
        //cityid - (required) the foursquare cityid where the venue is
        //phone - (optional) the phone number for the venue
        public static Venue AddVenue(string name, string address, string crossstreet, string city, string state, string zip, int cityid, string phone)
        {
            List<string> parameters = new List<string>();
            parameters.Add("name=" + name);
            parameters.Add("address=" + address);
            parameters.Add("crossstreet=" + crossstreet);
            parameters.Add("city=" + city);
            parameters.Add("state=" + state);
            parameters.Add("zip=" + zip);
            parameters.Add("cityid=" + cityid);
            parameters.Add("phone=" + phone);

            string json = APIRequest(API_VENUE, METHOD_GET, parameters);
            JObject jsonObject = JObject.Parse(json);
            Venue v = JsonConvert.DeserializeObject<Venue>(jsonObject["venue"].ToString());
            return v;
        }

        public static City CheckCity(double geolat, double geolong)
        {
            List<string> parameters = new List<string>();
            parameters.Add("geolat=" + geolat);
            parameters.Add("geolong=" + geolong);

            string json = APIRequest(API_CHECKCITY, METHOD_GET, parameters);
            JObject jsonObject = JObject.Parse(json);
            City c = JsonConvert.DeserializeObject<City>(jsonObject["city"].ToString());
            return c;
        }

        //vid - (optional, not necessary if you are 'shouting' or have a venue name). ID of the venue where you want to check-in.
        //venue - (optional, not necessary if you are 'shouting' or have a vid) if you don't have a venue ID, pass the venue name as a string using this parameter. foursquare will attempt to match it on the server-side
        //shout - (optional) a message about your check-in. the maximum length of this field is 140 characters
        //private - (optional). "1" means "don't show your friends". "0" means "show everyone"
        //twitter - (optional, default to the user's setting). "1" means "send to twitter". "0" means "don't send to twitter"
        //geolat - (optional, but recommended)
        //geolong - (optional, but recommended)
        public static string VenueCheckin(int vid, string venue, string shout, int isPrivate, int sendToTwitter, double geolat, double geolong)
        {
            List<string> parameters = new List<string>();
            if (vid > 0) parameters.Add("vid=" + vid);
            if (!String.IsNullOrEmpty(venue)) parameters.Add("venue=" + venue);
            if (!String.IsNullOrEmpty(shout)) parameters.Add("shout=" + shout);
            if (isPrivate > 0) parameters.Add("private=" + isPrivate);
            if (geolat > 0) parameters.Add("geolat=" + geolat);
            if (geolong > 0) parameters.Add("geolong=" + geolong);

            string json = APIRequest(API_CHECKIN, METHOD_POST, parameters);
            JObject checkin = JObject.Parse(json);
            return checkin["checkin"]["message"].ToString();
        }

        public static List<Checkin> GetCheckins()
        {
            string json = String.Empty;
            List<string> parameters = new List<string> { };
            FSOAuth.UserRequest(API_HOST + API_CHECKINS + API_FORMAT, String.Empty, String.Empty, OAuthToken, OAuthTokenSecret, parameters, "GET", out json);
            
            JObject checkins = JObject.Parse(json);
            List<Checkin> checkinList = JsonConvert.DeserializeObject<List<Checkin>>(checkins["checkins"].ToString());

            return checkinList;
        }

        public static List<Checkin> GetHistory()
        {
            string json = String.Empty;
            List<string> parameters = new List<string> { };
            FSOAuth.UserRequest(API_HOST + API_HISTORY + API_FORMAT, String.Empty, String.Empty, OAuthToken, OAuthTokenSecret, parameters, "GET", out json);

            JObject checkins = JObject.Parse(json);
            List<Checkin> checkinList = JsonConvert.DeserializeObject<List<Checkin>>(checkins["checkins"].ToString());

            return checkinList;
        }

        public static List<Venue> GetVenues(double geolat, double geolong)
        {
            List<string> parameters = new List<string>();
            parameters.Add("geolat=" + geolat);
            parameters.Add("geolong=" + geolong);
            string json = APIRequest(API_VENUES, METHOD_GET, parameters);
            
            JObject venues = JObject.Parse(json);
            List<Venue> venueList = JsonConvert.DeserializeObject<List<Venue>>(venues["groups"][0]["venues"].ToString());

            return venueList;
        }

        private static string APIRequest(string API_CALL, string method, List<string> parameters)
        {
            string json = String.Empty;
            string paramString = string.Join("&", parameters.ToArray());

            // Cache only GET requests
            if (method.Equals(METHOD_GET))
                json = FSLocal.GetJSON(API_CALL, paramString);

            if (String.IsNullOrEmpty(json))
            {
                FSOAuth.UserRequest(API_HOST + API_CALL + API_FORMAT, String.Empty, String.Empty, OAuthToken, OAuthTokenSecret, parameters, method, out json);

                FSLocal.SaveJSON(API_CALL, paramString, json);
            }
            return json;
        }

        //public static Image DownloadImage(string url)
        //{
        //    HttpWebRequest r = (HttpWebRequest)WebRequest.Create(url);
        //    HttpWebResponse res = (HttpWebResponse)r.GetResponse();
        //    Image img = new Bitmap(res.GetResponseStream());
        //    res.Close();
        //    return img;

        //}

        public static Image GetUserPhoto(User u)
        {
            string filepath = Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData) + @"\foursquare\images\";
            int namestart = u.photo.LastIndexOf('/') + 1;
            string filename = filepath + u.photo.Substring(namestart, u.photo.Length - namestart);
            Image img;

            try
            {
                if (File.Exists(filename))
                {
                    img = new Bitmap(filename);
                } else {
                    if (!File.Exists(filepath))
                        Directory.CreateDirectory(filepath);

                    HttpWebRequest r = (HttpWebRequest)WebRequest.Create(new Uri(u.photo));
                    HttpWebResponse res = (HttpWebResponse)r.GetResponse();
                    Stream stream = res.GetResponseStream();

                    FileStream streamFile = File.Create(filename);

                    byte[] buffer = new byte[1024];
                    int bytes;

                    bytes = stream.Read(buffer, 0, buffer.Length);
                    while (bytes > 0)
                    {
                        streamFile.Write(buffer, 0, bytes);
                        bytes = stream.Read(buffer, 0, buffer.Length);
                    }

                    res.Close();
                    streamFile.Close();
                    stream.Close();

                    img = new Bitmap(filename);
                }
            }
            catch (Exception ex)
            {
                img = new Bitmap(30, 30);
            }
            return img;
        }
    }
}
